package com.fdmgroup.benchmarker.lib.thread;

import com.fdmgroup.benchmarker.lib.common.BenchmarkResult;

public class ThreadPool {
	private int mPoolSize;
	private TaskThread[] mThreads;
	private BenchmarkTask mTask;
	private volatile Counter mThreadCounter;
	private Object mO;
	private Flag mIsRunning;

	public ThreadPool(int poolSize, BenchmarkTask task) {
		mPoolSize = poolSize;
		mTask = task;
		mThreadCounter = new Counter(0);
		mIsRunning = new Flag(true);
		mO = new Object();
	}

	public void initializePool() {
		mThreads = new TaskThread[mPoolSize];
		for (int i = 0; i < mPoolSize; i++) {
			mThreads[i] = new TaskThread(Integer.toString(i + 1), mTask,
					mThreadCounter,mIsRunning,mO);
			mThreadCounter.increment();
		}
	}

	public BenchmarkResult startPool(long period) {
		if (mThreads == null)
			throw new IllegalStateException(
					"Cannot start threads in thread pool as they have not been initialized");
		long before;
		synchronized(mO){
			for (int i = 0; i < mPoolSize; i++) {
				new Thread(mThreads[i]).start();
			}
			before = System.nanoTime() / 1000000;
			mO.notifyAll();
		}
		try {
			Thread.sleep(period);
		} catch (InterruptedException e) {
		}
		mIsRunning.turnOff();
		long after = System.nanoTime() / 1000000;
		synchronized (mThreadCounter) {
			while (mThreadCounter.isGreaterThanZero()) {
				try {
					mThreadCounter.wait();
				} catch (InterruptedException e) {
				}
			}
		}
		long duration = after - before;

		return new BenchmarkResult(getTotalTaskPerformed(), duration);
	}

	private long getTotalTaskPerformed() {
		long total = 0;
		for (int i = 0; i < mPoolSize; i++) {
			total += mThreads[i].getNumberOfTasksPerformed();
		}
		return total;
	}
}
